package dfa;

import fa.FARule;
import org.junit.jupiter.api.Test;

import java.util.Arrays;
import java.util.List;
import java.util.Set;

import static org.junit.jupiter.api.Assertions.*;

/**
 * @author haoly
 * @title DFATest
 * @date 2025/4/16 12:04
 * @description DFATest
 */
public class DFATest {
    @Test
    void testAccepting() {
        List<FARule<Integer>> rules = Arrays.asList(
                new FARule<>(1, 'a', 2),
                new FARule<>(1, 'b', 1),
                new FARule<>(2, 'a', 2),
                new FARule<>(2, 'b', 3),
                new FARule<>(3, 'a', 3),
                new FARule<>(3, 'b', 3)
        );
        DFARulebook<Integer> rulebook = new DFARulebook<>(rules);

        DFA<Integer> dfa1 = new DFA<>(1, Set.of(1,3), rulebook);
        assertTrue(dfa1.accepting());

        DFA<Integer> dfa2 = new DFA<>(1, Set.of(3), rulebook);
        assertFalse(dfa2.accepting());
    }

    @Test
    void testReadCharacter() {
        List<FARule<Integer>> rules = Arrays.asList(
                new FARule<>(1, 'a', 2),
                new FARule<>(1, 'b', 1),
                new FARule<>(2, 'a', 2),
                new FARule<>(2, 'b', 3),
                new FARule<>(3, 'a', 3),
                new FARule<>(3, 'b', 3)
        );
        DFARulebook<Integer> rulebook = new DFARulebook<>(rules);

        DFA<Integer> dfa = new DFA<>(1, Set.of(3), rulebook);
        assertFalse(dfa.accepting());

        dfa.readCharacter('b');
        assertEquals(1, dfa.getCurrentState());
        assertFalse(dfa.accepting());

        for (int i = 0; i < 3; i++) {
            dfa.readCharacter('a');
        }
        assertEquals(2, dfa.getCurrentState());
        assertFalse(dfa.accepting());

        dfa.readCharacter('b');
        assertEquals(3, dfa.getCurrentState());
        assertTrue(dfa.accepting());
    }

    @Test
    void testReadString() {
        List<FARule<Integer>> rules = Arrays.asList(
                new FARule<>(1, 'a', 2),
                new FARule<>(1, 'b', 1),
                new FARule<>(2, 'a', 2),
                new FARule<>(2, 'b', 3),
                new FARule<>(3, 'a', 3),
                new FARule<>(3, 'b', 3)
        );
        DFARulebook<Integer> rulebook = new DFARulebook<>(rules);

        DFA<Integer> dfa = new DFA<>(1, Set.of(3), rulebook);
        assertFalse(dfa.accepting());

        dfa.readString("baaab");
        assertEquals(3, dfa.getCurrentState());
        assertTrue(dfa.accepting());
    }
}
